#include "SdkVideo.h"

#define DEF_TAG         "Venc"

static Com_s8 g_SdkVideo_Pic_Flag = DEF_COM_FALSE;
static unsigned char g_SdkVideo_Start_Venc;

int g_SdkVideo_Osd_Enable = 3;
int g_SdkVideo_DirectSwitch = 0;
const IMPEncoderRcMode g_SdkVideo_S_RC_METHOD = IMP_ENC_RC_MODE_CBR;
int g_SdkVideo_VencFd[FS_CHN_NUM];
int g_SdkVideo_MaxVencFd = 0;
char g_SdkVideo_Buf[DEF_SDK_MAX_FRAME_SIZE];
IMPEncoderStream g_SdkVideo_Stream;
IMPFrameInfo *g_SdkVideo_Frame_Bak;
IMPRgnHandle g_SdkVideo_Osd_Hander[FS_CHN_NUM][5];

struct chn_conf chn[FS_CHN_NUM] = {
    {
        .index = CH0_INDEX,
        .enable = CHN0_EN,
        .payloadType = IMP_ENC_PROFILE_HEVC_MAIN,
        .fs_chn_attr = {
            .i2dattr.i2d_enable = 0,
            .i2dattr.flip_enable = 0,
            .i2dattr.mirr_enable = 0,
            .i2dattr.rotate_enable = 1,
            .i2dattr.rotate_angle = 90,

            .pixFmt = PIX_FMT_NV12,
            .outFrmRateNum = FIRST_SENSOR_FRAME_RATE_NUM,
            .outFrmRateDen = FIRST_SENSOR_FRAME_RATE_DEN,
            .nrVBs = 2,
            .type = FS_PHY_CHANNEL,

            .crop.enable = FIRST_CROP_EN,
            .crop.top = 0,
            /** 32 byte 对齐 **/
            .crop.left = 0,
            .crop.width = SENSOR_MAIN_WIDTH,
            .crop.height = SENSOR_MAIN_HEIGHT,

            .scaler.enable = 1,
            .scaler.outwidth = SENSOR_MAIN_WIDTH,
            .scaler.outheight = SENSOR_MAIN_HEIGHT,

            .fcrop.enable = 0,
            .fcrop.top = 0,
            .fcrop.left = 0,
            .fcrop.width = SENSOR_MAIN_WIDTH,
            .fcrop.height = SENSOR_MAIN_HEIGHT,

            .picWidth = SENSOR_MAIN_WIDTH,
            .picHeight = SENSOR_MAIN_HEIGHT,
        },
        .framesource_chn =	{ DEV_ID_FS, CH0_INDEX, 0},
        .imp_encoder = { DEV_ID_ENC, CH0_INDEX, 0},
    },
    {
        .index = CH1_INDEX,
        .enable = CHN1_EN,
        .payloadType = IMP_ENC_PROFILE_HEVC_MAIN,
        .fs_chn_attr = {
            .i2dattr.i2d_enable = 0,
            .i2dattr.flip_enable = 0,
            .i2dattr.mirr_enable = 0,
            .i2dattr.rotate_enable = 1,
            .i2dattr.rotate_angle = 90,

            .pixFmt = PIX_FMT_NV12,
            .outFrmRateNum = FIRST_SENSOR_FRAME_RATE_NUM,
            .outFrmRateDen = FIRST_SENSOR_FRAME_RATE_DEN,
            .nrVBs = 2,
            .type = FS_PHY_CHANNEL,

            .crop.enable = FIRST_CROP_EN,
            .crop.top = 0,
            .crop.left = 0,
            .crop.width = SENSOR_SUB_WIDTH,
            .crop.height = SENSOR_SUB_HEIGHT,

            .scaler.enable = 1,
            .scaler.outwidth = SENSOR_SUB_WIDTH,
            .scaler.outheight = SENSOR_SUB_HEIGHT,

            .picWidth = SENSOR_SUB_WIDTH,
            .picHeight = SENSOR_SUB_HEIGHT,
        },
        .framesource_chn =	{ DEV_ID_FS, CH1_INDEX, 0},
        .imp_encoder = { DEV_ID_ENC, CH1_INDEX, 0},
    },
    {
        .index = CH2_INDEX,
        .enable = CHN2_EN,
        .payloadType = IMP_ENC_PROFILE_HEVC_MAIN,
        .fs_chn_attr =
        {
            .i2dattr.i2d_enable = 0,
            .i2dattr.flip_enable = 0,
            .i2dattr.mirr_enable = 0,
            .i2dattr.rotate_enable = 1,
            .i2dattr.rotate_angle = 90,

            .pixFmt = PIX_FMT_NV12,
            .outFrmRateNum = DEF_PERSONVEHICLEPETDET_FRAME,
            .outFrmRateDen = FIRST_SENSOR_FRAME_RATE_DEN,
            .nrVBs = 3,
            .type = FS_PHY_CHANNEL,

            .crop.enable = 0,
            .crop.top = 0,
            .crop.left = 0,
            .crop.width = SENSOR_MAIN_WIDTH,
            .crop.height = SENSOR_MAIN_HEIGHT,

            .scaler.enable = 1,
            .scaler.outwidth = DEF_PERSONVEHICLEPETDET_WIDTH,
            .scaler.outheight = DEF_PERSONVEHICLEPETDET_HEIGHT,

            .picWidth = DEF_PERSONVEHICLEPETDET_WIDTH,
            .picHeight = DEF_PERSONVEHICLEPETDET_HEIGHT,
        },
        .framesource_chn =	{ DEV_ID_FS, CH2_INDEX, 0},
        .imp_encoder = { DEV_ID_ENC, CH2_INDEX, 0},
    }
};

IMPSensorInfo Def_Sensor_Info[1] = {
    {
        FIRST_SNESOR_NAME,
        TX_SENSOR_CONTROL_INTERFACE_I2C,
        .i2c = {FIRST_SNESOR_NAME, FIRST_I2C_ADDR, FIRST_I2C_ADAPTER_ID},
        FIRST_RST_GPIO,
        FIRST_PWDN_GPIO,
        FIRST_POWER_GPIO,
        FIRST_SENSOR_ID,
        FIRST_VIDEO_INTERFACE,
        FIRST_MCLK,
        FIRST_DEFAULT_BOOT
    }
};

IMPSensorInfo sensor_info[1];

int ChipSdk_Jpeg_Init(void)
{
    int i, ret;
    IMPEncoderChnAttr channel_attr;
    IMPFSChnAttr *imp_chn_attr_tmp;

    for (i = 0; i <  1; i++)
    {
        if (chn[i].enable)
        {
            int s32picWidth, s32picHeight;
            IMPFSI2DAttr sti2dattr;
            ret = IMP_FrameSource_GetI2dAttr(chn[i].index, &sti2dattr);
            if(ret == 0)
            {
                if((1 == sti2dattr.i2d_enable) &&
                    ((sti2dattr.rotate_enable) && (sti2dattr.rotate_angle == 90 || sti2dattr.rotate_angle == 270)))
                {
                    s32picWidth = (chn[i].fs_chn_attr.picHeight); /*this depend on your sensor or channels*/
                    s32picHeight = (chn[i].fs_chn_attr.picWidth);
                }
                else
                {
                    s32picWidth = chn[i].fs_chn_attr.picWidth;
                    s32picHeight = chn[i].fs_chn_attr.picHeight;
                }
            } else {
                s32picWidth = chn[i].fs_chn_attr.picWidth;
                s32picHeight = chn[i].fs_chn_attr.picHeight;
            }
            PRT_DBG(DEF_TAG,"jpeg_init: s32picWidth = %d, s32picHeight = %d\n", s32picWidth, s32picHeight);
            
            imp_chn_attr_tmp = &chn[i].fs_chn_attr;
            memset(&channel_attr, 0, sizeof(IMPEncoderChnAttr));
            ret = IMP_Encoder_SetDefaultParam(&channel_attr, IMP_ENC_PROFILE_JPEG, IMP_ENC_RC_MODE_FIXQP,
                                              s32picWidth, s32picHeight,
                                              imp_chn_attr_tmp->outFrmRateNum, imp_chn_attr_tmp->outFrmRateDen,
                                              0, 0, 25, 0);

            /* Create Channel */
            ret = IMP_Encoder_CreateChn(4 + chn[i].index, &channel_attr);
            if (ret < 0) {
                PRT_ERR(DEF_TAG, "IMP_Encoder_CreateChn(%d) error: %d\n",
                            chn[i].index, ret);
                return -1;
            }

            /* Resigter Channel */
            ret = IMP_Encoder_RegisterChn(i, 4 + chn[i].index);
            if (ret < 0) {
                PRT_ERR(DEF_TAG, "IMP_Encoder_RegisterChn(0, %d) error: %d\n",
                           chn[i].index, ret);
                return -1;
            }
        }
    }

    return 0;
}

int ChipSdk_Jpeg_Exit(void)
{
    int ret = 0, i = 0, chnNum = 0;
    IMPEncoderChnStat chn_stat;

    for (i = 0; i <  1; i++)
    {
        if (chn[i].enable)
        {
            chnNum = 4 + chn[i].index;
            memset(&chn_stat, 0, sizeof(IMPEncoderChnStat));
            ret = IMP_Encoder_Query(chnNum, &chn_stat);
            if (ret < 0)
            {
                PRT_ERR(DEF_TAG, "IMP_Encoder_Query(%d) error: %d\n", chnNum, ret);
                return -1;
            }

            if (chn_stat.registered)
            {
                ret = IMP_Encoder_UnRegisterChn(chnNum);
                if (ret < 0)
                {
                    PRT_ERR(DEF_TAG, "IMP_Encoder_UnRegisterChn(%d) error: %d\n", chnNum, ret);
                    return -1;
                }

                ret = IMP_Encoder_DestroyChn(chnNum);
                if (ret < 0)
                {
                    PRT_ERR(DEF_TAG, "IMP_Encoder_DestroyChn(%d) error: %d\n", chnNum, ret);
                    return -1;
                }
            }
        }
    }

    return 0;
}

void Sdk_Video_Set_Sensor_Type(void)
{
    if(Ext_InComFile_Access(DEF_SENSOR_INFO_GC2083) == DEF_COM_FILE_EXIST)
    {
        PRT_INFO(DEF_TAG,"sensor is gc2083\n");
        strcpy(Def_Sensor_Info[0].name,CHIPSDK_SENSOR_NAME_GC2083);
        Def_Sensor_Info[0].i2c.addr = CHIPSDK_I2C_ADDR_GC2083;
    }
}

int ChipSdk_System_Init(void)
{
    int ret = 0;

    IMP_LOG_DBG(DEF_TAG, "ChipSdk_System_Init start\n");
    Sdk_Video_Set_Sensor_Type();

    /* isp osd and ipu osd buffer size set */
    if(1 == g_SdkVideo_Osd_Enable)
    { /* only use ipu osd */
        IMP_OSD_SetPoolSize(512*1024);
    }
    else if(2 == g_SdkVideo_Osd_Enable)
    { /* only use isp osd */
        IMP_ISP_Tuning_SetOsdPoolSize(512 * 1024);
    }
    else if(3 == g_SdkVideo_Osd_Enable)
    { /* use ipu osd and isp osd */
        IMP_OSD_SetPoolSize(512*1024);
        IMP_ISP_Tuning_SetOsdPoolSize(512 * 1024);
    }
    memset(&sensor_info, 0, sizeof(sensor_info));
    memcpy(&sensor_info[0], &Def_Sensor_Info[0], sizeof(IMPSensorInfo));

    /* open isp */
    ret = IMP_ISP_Open();
    if(ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "failed to open ISP\n");
        return -1;
    }

    /* add sensor */
    ret = IMP_ISP_AddSensor(IMPVI_MAIN, &sensor_info[0]);
    if(ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "failed to AddSensor\n");
        return -1;
    }

    /* enable sensor */
    ret = IMP_ISP_EnableSensor(IMPVI_MAIN, &sensor_info[0]);
    if(ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "failed to EnableSensor\n");
        return -1;
    }

    /* init imp system */
    ret = IMP_System_Init();
    if(ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_System_Init failed\n");
        return -1;
    }

    /* enable turning, to debug graphics */
    ret = IMP_ISP_EnableTuning();
    if(ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_EnableTuning failed\n");
        return -1;
    }

    IMPISPBinAttr switch_bin_attr;

    memset(&switch_bin_attr,0,sizeof(switch_bin_attr));
    switch_bin_attr.enable = IMPISP_TUNING_OPS_MODE_ENABLE;

    sprintf(switch_bin_attr.bname,"/tmp/%s-t41.bin",Def_Sensor_Info[0].name);
    if(Ext_InComFile_Access(switch_bin_attr.bname) == DEF_COM_FILE_NOT_EXIST)
    {
        memset(switch_bin_attr.bname,0,sizeof(switch_bin_attr.bname));
        sprintf(switch_bin_attr.bname,"/appfs/configs/%s-t41.bin",Def_Sensor_Info[0].name);

        if(Ext_InComFile_Access(switch_bin_attr.bname) == DEF_COM_FILE_NOT_EXIST)
        {
            PRT_INFO(DEF_TAG,"etc sensor isp\n");
            memset(switch_bin_attr.bname,0,sizeof(switch_bin_attr.bname));
            sprintf(switch_bin_attr.bname,"/etc/sensor/%s-t41.bin",Def_Sensor_Info[0].name);
        }
        else
        {
            PRT_INFO(DEF_TAG,"appfs sensor isp\n");
        }
    }
    else
    {
        PRT_INFO(DEF_TAG,"tmp test sensor isp\n");
    }

    IMP_ISP_Tuning_SwitchBin(IMPVI_MAIN,&switch_bin_attr);
    if(ret)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_Tuning_SwitchBin error !\n");
        return -1;
    }

    /* set contrast, sharpness, saturation, brightness */
    unsigned char value = 128;
    IMP_ISP_Tuning_SetContrast(IMPVI_MAIN, &value);
    IMP_ISP_Tuning_SetSharpness(IMPVI_MAIN, &value);
    IMP_ISP_Tuning_SetSaturation(IMPVI_MAIN, &value);
    IMP_ISP_Tuning_SetBrightness(IMPVI_MAIN, &value);

    /* set runningmode */
    IMPISPRunningMode dn = IMPISP_RUNNING_MODE_DAY;
    ret = IMP_ISP_Tuning_SetISPRunningMode(IMPVI_MAIN, &dn);
    if (ret < 0){
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_Tuning_SetISPRunningMode failed\n");
        return -1;
    }

    /* set fps */
    IMPISPSensorFps fpsAttr;
    fpsAttr.num = FIRST_SENSOR_FRAME_RATE_NUM;
    fpsAttr.den = FIRST_SENSOR_FRAME_RATE_DEN;
    ret = IMP_ISP_Tuning_SetSensorFPS(0, &fpsAttr);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_Tuning_SetSensorFPS failed\n");
        return -1;
    }

    IMP_LOG_DBG(DEF_TAG, "ChipSdk_System_Init success\n");

    return 0;
}

int ChipSdk_System_Exit(void)
{
    IMP_LOG_DBG(DEF_TAG, "system exit start\n");

    int ret = 0;

    /* exit imp system */
    ret = IMP_System_Exit();
    if(ret < 0){
        IMP_LOG_ERR(DEF_TAG, "IMP_System_Exit failed\n");
        return -1;
    }

    /* disable sensor */
    ret = IMP_ISP_DisableSensor(IMPVI_MAIN);
    if(ret < 0){
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_DisableSensor failed\n");
        return -1;
    }

    /* delete sensor */
    ret = IMP_ISP_DelSensor(IMPVI_MAIN, &sensor_info[0]);
    if(ret < 0){
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_DelSensor failed\n");
        return -1;
    }

    /* disable turning */
    ret = IMP_ISP_DisableTuning();
    if(ret < 0){
        IMP_LOG_ERR(DEF_TAG, "IMP_ISP_DisableTuning failed\n");
        return -1;
    }

    /* close isp */
    ret = IMP_ISP_Close();
    if(ret < 0){
        IMP_LOG_ERR(DEF_TAG, "failed to open ISP\n");
        return -1;
    }

    IMP_LOG_DBG(DEF_TAG, " system exit success\n");

    return 0;
}

int ChipSdk_FrameSource_Init(void)
{
    IMP_LOG_DBG(DEF_TAG, "Frame Source Init start\n");

    int i, ret;

    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = IMP_FrameSource_CreateChn(chn[i].index, &chn[i].fs_chn_attr);
            if(ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_FrameSource_CreateChn(chn%d) error !\n", chn[i].index);
                return -1;
            }

            ret = IMP_FrameSource_SetChnAttr(chn[i].index, &chn[i].fs_chn_attr);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_FrameSource_SetChnAttr(chn%d) error !\n",  chn[i].index);
                return -1;
            }
        }
    }

    IMP_LOG_DBG(DEF_TAG, "Frame Source Init success\n");

    return 0;
}

int ChipSdk_FrameSource_Exit(void)
{
    IMP_LOG_DBG(DEF_TAG, "Frame Source Exit start\n");

    int i, ret;

    /* destroy framesource channels */
    for (i = 0; i <  FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = IMP_FrameSource_DestroyChn(chn[i].index);
            if (ret < 0) {
                IMP_LOG_ERR(DEF_TAG, "IMP_FrameSource_DestroyChn(%d) error: %d\n", chn[i].index, ret);
                return -1;
            }
        }
    }

    IMP_LOG_DBG(DEF_TAG, "Frame Source Exit success\n");

    return 0;
}

int ChipSdk_Encoder_Init(void)
{
    IMP_LOG_DBG(DEF_TAG, "Encoder Init start\n");

    int i, ret, chnNum = 0;
    int s32picWidth = 0,s32picHeight = 0;
    IMPFSChnAttr *imp_chn_attr_tmp;
    IMPEncoderChnAttr channel_attr;
    IMPFSI2DAttr sti2dattr;
    for (i = 0; i <  FS_CHN_NUM; i++)
    {
        if(i == CH2_INDEX)
        {
            continue;
        }

        if (chn[i].enable)
        {
            imp_chn_attr_tmp = &chn[i].fs_chn_attr;
            chnNum = chn[i].index;

            memset(&channel_attr, 0, sizeof(IMPEncoderChnAttr));
            memset(&sti2dattr,0,sizeof(IMPFSI2DAttr));

            ret = IMP_FrameSource_GetI2dAttr(chn[i].index,&sti2dattr);
            if(ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_FrameSource_GetI2dAttr(%d) error !\n", chn[i].index);
                return -1;
            }

            if((1 == sti2dattr.i2d_enable) && ((sti2dattr.rotate_enable) && (sti2dattr.rotate_angle == 90 || sti2dattr.rotate_angle == 270)))
            {
                /* this depend on your sensor or channels */
                // s32picWidth = (chn[i].fs_chn_attr.picHeight +15) & (~15);
                // s32picHeight = (chn[i].fs_chn_attr.picWidth +15) & (~15);
                s32picWidth = (chn[i].fs_chn_attr.picHeight);
                s32picHeight = (chn[i].fs_chn_attr.picWidth);
            }
            else
            {
                s32picWidth = chn[i].fs_chn_attr.picWidth;
                s32picHeight =chn[i].fs_chn_attr.picHeight;
            }

            float ratio = 1;
            if (((uint64_t)s32picWidth * s32picHeight) > (1280 * 720))
            {
                ratio = log10f(((uint64_t)s32picWidth * s32picHeight) / (1280 * 720.0)) + 1;
            }
            else
            {
                ratio = 1.0 / (log10f((1280 * 720.0) / ((uint64_t)s32picWidth * s32picHeight)) + 1);
            }

            ratio = ratio > 0.1 ? ratio : 0.1;
            //unsigned int uTargetBitRate = BITRATE_720P_Kbs * ratio;
            unsigned int uTargetBitRate = BITRATE_720P_Kbs;
            PRT_DBG(DEF_TAG,"rcMode: %d\n", g_SdkVideo_S_RC_METHOD);
            ret = IMP_Encoder_SetDefaultParam(&channel_attr, chn[i].payloadType, g_SdkVideo_S_RC_METHOD,
                    s32picWidth, s32picHeight,imp_chn_attr_tmp->outFrmRateNum, imp_chn_attr_tmp->outFrmRateDen,
                    imp_chn_attr_tmp->outFrmRateNum / imp_chn_attr_tmp->outFrmRateDen, 2,
                    (g_SdkVideo_S_RC_METHOD == IMP_ENC_RC_MODE_FIXQP) ? 35 : -1, uTargetBitRate);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_SetDefaultParam(%d) error !\n", chnNum);
                return -1;
            }
#ifdef LOW_BITSTREAM
            IMPEncoderRcAttr *rcAttr = &channel_attr.rcAttr;
            uTargetBitRate /= 2;

            switch (rcAttr->attrRcMode.rcMode) {
                case IMP_ENC_RC_MODE_FIXQP:
                    rcAttr->attrRcMode.attrFixQp.iInitialQP = 38;
                    break;
                case IMP_ENC_RC_MODE_CBR:
                    rcAttr->attrRcMode.attrCbr.uTargetBitRate = uTargetBitRate;
                    rcAttr->attrRcMode.attrCbr.iInitialQP = -1;
                    rcAttr->attrRcMode.attrCbr.iMinQP = 34;
                    rcAttr->attrRcMode.attrCbr.iMaxQP = 51;
                    rcAttr->attrRcMode.attrCbr.iIPDelta = -1;
                    rcAttr->attrRcMode.attrCbr.iPBDelta = -1;
                    rcAttr->attrRcMode.attrCbr.eRcOptions = IMP_ENC_RC_SCN_CHG_RES | IMP_ENC_RC_OPT_SC_PREVENTION;
                    rcAttr->attrRcMode.attrCbr.uMaxPictureSize = uTargetBitRate * 4 / 3;
                    break;
                case IMP_ENC_RC_MODE_VBR:
                    rcAttr->attrRcMode.attrVbr.uTargetBitRate = uTargetBitRate;
                    rcAttr->attrRcMode.attrVbr.uMaxBitRate = uTargetBitRate * 4 / 3;
                    rcAttr->attrRcMode.attrVbr.iInitialQP = -1;
                    rcAttr->attrRcMode.attrVbr.iMinQP = 34;
                    rcAttr->attrRcMode.attrVbr.iMaxQP = 51;
                    rcAttr->attrRcMode.attrVbr.iIPDelta = -1;
                    rcAttr->attrRcMode.attrVbr.iPBDelta = -1;
                    rcAttr->attrRcMode.attrVbr.eRcOptions = IMP_ENC_RC_SCN_CHG_RES | IMP_ENC_RC_OPT_SC_PREVENTION;
                    rcAttr->attrRcMode.attrVbr.uMaxPictureSize = uTargetBitRate * 4 / 3;
                    break;
                case IMP_ENC_RC_MODE_CAPPED_VBR:
                    rcAttr->attrRcMode.attrCappedVbr.uTargetBitRate = uTargetBitRate;
                    rcAttr->attrRcMode.attrCappedVbr.uMaxBitRate = uTargetBitRate * 4 / 3;
                    rcAttr->attrRcMode.attrCappedVbr.iInitialQP = -1;
                    rcAttr->attrRcMode.attrCappedVbr.iMinQP = 34;
                    rcAttr->attrRcMode.attrCappedVbr.iMaxQP = 51;
                    rcAttr->attrRcMode.attrCappedVbr.iIPDelta = -1;
                    rcAttr->attrRcMode.attrCappedVbr.iPBDelta = -1;
                    rcAttr->attrRcMode.attrCappedVbr.eRcOptions = IMP_ENC_RC_SCN_CHG_RES | IMP_ENC_RC_OPT_SC_PREVENTION;
                    rcAttr->attrRcMode.attrCappedVbr.uMaxPictureSize = uTargetBitRate * 4 / 3;
                    rcAttr->attrRcMode.attrCappedVbr.uMaxPSNR = 42;
                    break;
                case IMP_ENC_RC_MODE_CAPPED_QUALITY:
                    rcAttr->attrRcMode.attrCappedQuality.uTargetBitRate = uTargetBitRate;
                    rcAttr->attrRcMode.attrCappedQuality.uMaxBitRate = uTargetBitRate * 4 / 3;
                    rcAttr->attrRcMode.attrCappedQuality.iInitialQP = -1;
                    rcAttr->attrRcMode.attrCappedQuality.iMinQP = 34;
                    rcAttr->attrRcMode.attrCappedQuality.iMaxQP = 51;
                    rcAttr->attrRcMode.attrCappedQuality.iIPDelta = -1;
                    rcAttr->attrRcMode.attrCappedQuality.iPBDelta = -1;
                    rcAttr->attrRcMode.attrCappedQuality.eRcOptions = IMP_ENC_RC_SCN_CHG_RES | IMP_ENC_RC_OPT_SC_PREVENTION;
                    rcAttr->attrRcMode.attrCappedQuality.uMaxPictureSize = uTargetBitRate * 4 / 3;
                    rcAttr->attrRcMode.attrCappedQuality.uMaxPSNR = 42;
                    break;
                case IMP_ENC_RC_MODE_INVALID:
                    IMP_LOG_ERR(DEF_TAG, "unsupported rcmode:%d, we only support fixqp, cbr vbr and capped vbr\n", rcAttr->attrRcMode.rcMode);
                    return -1;
            }
#endif
            if(g_SdkVideo_DirectSwitch == 1)
            {
                if (0 == chnNum)
                {
                    channel_attr.bEnableIvdc = true;
                }
            }

            ret = IMP_Encoder_CreateChn(chnNum, &channel_attr);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_CreateChn(%d) error !\n", chnNum);
                return -1;
            }

            ret = IMP_Encoder_RegisterChn(chn[i].index, chnNum);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_RegisterChn(%d, %d) error: %d\n", chn[i].index, chnNum, ret);
                return -1;
            }

            g_SdkVideo_VencFd[i] = IMP_Encoder_GetFd(chnNum);
            if (g_SdkVideo_VencFd[i] < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_GetFd(%d) failed\n", chnNum);
                return -1;
            }

            if (g_SdkVideo_MaxVencFd < g_SdkVideo_VencFd[i])
            {
                g_SdkVideo_MaxVencFd = g_SdkVideo_VencFd[i];
            }

            ret = IMP_Encoder_StartRecvPic(chnNum);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_StartRecvPic(%d) failed\n", chnNum);
                return -1;
            }
        }
    }

    IMP_LOG_DBG(DEF_TAG, "Encoder Init success\n");

    return 0;
}

int ChipSdk_Encoder_Exit(void)
{
    IMP_LOG_DBG(DEF_TAG, "Encoder Exit start\n");

    int ret = 0, i = 0, chnNum = 0;
    IMPEncoderChnStat chn_stat;

    for (i = 0; i <  FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            chnNum = chn[i].index;

            memset(&chn_stat, 0, sizeof(IMPEncoderChnStat));

            ret = IMP_Encoder_StopRecvPic(chnNum);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_StopRecvPic(%d) failed\n", chnNum);
                return -1;
            }

            ret = IMP_Encoder_Query(chnNum, &chn_stat);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_Query(%d) error: %d\n", chnNum, ret);
                return -1;
            }

            if (chn_stat.registered) {
                ret = IMP_Encoder_UnRegisterChn(chnNum);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_UnRegisterChn(%d) error: %d\n", chnNum, ret);
                    return -1;
                }

                ret = IMP_Encoder_DestroyChn(chnNum);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_DestroyChn(%d) error: %d\n", chnNum, ret);
                    return -1;
                }

                ret = IMP_Encoder_DestroyGroup(chnNum);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_DestroyGroup(%d) error: %d\n", chnNum, ret);
                    return -1;
                }
            }
        }
    }

    IMP_LOG_DBG(DEF_TAG, "Encoder Exit success\n");

    return 0;
}

int ChipSdk_FrameSource_StreamOn(void)
{
    int ret = 0, i = 0;

    /* enable framesource channels */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = IMP_FrameSource_EnableChn(chn[i].index);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_FrameSource_EnableChn failed, error chn index: %d\n", chn[i].index);
                return -1;
            }
        }
    }

    return 0;
}

int ChipSdk_FrameSource_StreamOff(void)
{
    int ret = 0, i = 0;

    /* disable framesource channels */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = IMP_FrameSource_DisableChn(chn[i].index);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_FrameSource_DisableChn failed, error chn index: %d\n", chn[i].index);
                return -1;
            }
        }
    }

    return 0;
}

int ChipSdk_Osd_Init(int grpNum)
{
    int ret = 0;
    IMPRgnHandle rHanderFont = 0;
    IMPRgnHandle rHanderLogo = 0;
    IMPRgnHandle rHanderCover = 0;
    IMPRgnHandle rHanderRect = 0;
    IMPRgnHandle rHanderLine = 0;

    rHanderFont = IMP_OSD_CreateRgn(NULL);
    if (rHanderFont == INVHANDLE)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_CreateRgn TimeStamp error !\n");
        return -1;
    }

    //query osd rgn create status
    IMPOSDRgnCreateStat stStatus;
    memset(&stStatus,0x0,sizeof(IMPOSDRgnCreateStat));
    ret = IMP_OSD_RgnCreate_Query(rHanderFont,&stStatus);
    if(ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_RgnCreate_Query error !\n");
        return -1;
    }

    rHanderLogo = IMP_OSD_CreateRgn(NULL);
    if (rHanderLogo == INVHANDLE)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_CreateRgn Logo error !\n");
        return -1;
    }

    rHanderCover = IMP_OSD_CreateRgn(NULL);
    if (rHanderCover == INVHANDLE)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_CreateRgn Cover error !\n");
        return -1;
    }

    rHanderRect = IMP_OSD_CreateRgn(NULL);
    if (rHanderRect == INVHANDLE)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_CreateRgn Rect error !\n");
        return -1;
    }

    rHanderLine = IMP_OSD_CreateRgn(NULL);
    if (rHanderLine == INVHANDLE)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_CreateRgn Line error !\n");
        return -1;
    }

    ret = IMP_OSD_RegisterRgn(rHanderFont, grpNum, NULL);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IVS IMP_OSD_RegisterRgn failed\n");
        return -1;
    }

    //query osd rgn register status
    IMPOSDRgnRegisterStat stRigStatus;
    memset(&stRigStatus,0x0,sizeof(IMPOSDRgnRegisterStat));
    ret = IMP_OSD_RgnRegister_Query(rHanderFont, grpNum,&stRigStatus);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_RgnRegister_Query failed\n");
        return -1;
    }

    ret = IMP_OSD_RegisterRgn(rHanderLogo, grpNum, NULL);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IVS IMP_OSD_RegisterRgn failed\n");
        return -1;
    }

    ret = IMP_OSD_RegisterRgn(rHanderCover, grpNum, NULL);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IVS IMP_OSD_RegisterRgn failed\n");
        return -1;
    }

    ret = IMP_OSD_RegisterRgn(rHanderRect, grpNum, NULL);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IVS IMP_OSD_RegisterRgn failed\n");
        return -1;
    }

    ret = IMP_OSD_RegisterRgn(rHanderLine, grpNum, NULL);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IVS IMP_OSD_RegisterRgn failed\n");
        return -1;
    }

    /* Font */
    IMPOSDRgnAttr rAttrFont;
    memset(&rAttrFont, 0, sizeof(IMPOSDRgnAttr));
    rAttrFont.type = OSD_REG_BITMAP;
    rAttrFont.rect.p0.x = 10;
    rAttrFont.rect.p0.y = 10;

    /** p0 is start，and p1 well be epual p0+width(or heigth)-1 **/
    rAttrFont.rect.p1.x = rAttrFont.rect.p0.x + 20 * OSD_REGION_WIDTH - 1;
    rAttrFont.rect.p1.y = rAttrFont.rect.p0.y + OSD_REGION_HEIGHT - 1;

    rAttrFont.fmt = PIX_FMT_MONOWHITE;
    rAttrFont.data.bitmapData = NULL;
    ret = IMP_OSD_SetRgnAttr(rHanderFont, &rAttrFont);
    if (ret < 0) {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetRgnAttr TimeStamp error !\n");
        return -1;
    }
    IMPOSDGrpRgnAttr grAttrFont;
    if (IMP_OSD_GetGrpRgnAttr(rHanderFont, grpNum, &grAttrFont) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_GetGrpRgnAttr Logo error !\n");
        return -1;
    }
    memset(&grAttrFont, 0, sizeof(IMPOSDGrpRgnAttr));
    grAttrFont.show = 0;
    /* Disable Font global alpha, only use pixel alpha. */
    grAttrFont.gAlphaEn = 1;
    grAttrFont.fgAlhpa = 0xff;
    grAttrFont.layer = 3;
    if (IMP_OSD_SetGrpRgnAttr(rHanderFont, grpNum, &grAttrFont) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetGrpRgnAttr Logo error !\n");
        return -1;
    }

    /* Logo */
    IMPOSDRgnAttr rAttrLogo;
    memset(&rAttrLogo, 0, sizeof(IMPOSDRgnAttr));
    int picw = 192;
    int pich = 60;

    rAttrLogo.rect.p0.x = 10;
    rAttrLogo.rect.p0.y = 10;

    if(grpNum == 0)
    {
        picw = DEF_OSD_LOGO_WIDTH;
        pich = DEF_OSD_LOGO_HEIGHT;
    }
    else if (grpNum == 1)
    {
        picw = DEF_OSD_LOGO_WIDTH_SEC;
        pich = DEF_OSD_LOGO_HEIGHT_SEC;
    }

    rAttrLogo.type = OSD_REG_PIC;
    //p0 is start，and p1 well be epual p0+width(or heigth)-1
    rAttrLogo.rect.p1.x = rAttrLogo.rect.p0.x + picw - 1;
    rAttrLogo.rect.p1.y = rAttrLogo.rect.p0.y + pich - 1;
    rAttrLogo.fmt = PIX_FMT_BGRA;

    if(grpNum == 0)
    {
        rAttrLogo.data.picData.pData = g_logo_data_main_catlink;
    }
    else if (grpNum == 1)
    {
        rAttrLogo.data.picData.pData = g_logo_data_sub_catlink;
    }

    ret = IMP_OSD_SetRgnAttr(rHanderLogo, &rAttrLogo);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetRgnAttr Logo error !\n");
        return -1;
    }

    IMPOSDGrpRgnAttr grAttrLogo;
    if (IMP_OSD_GetGrpRgnAttr(rHanderLogo, grpNum, &grAttrLogo) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_GetGrpRgnAttr Logo error !\n");
        return -1;
    }
    memset(&grAttrLogo, 0, sizeof(IMPOSDGrpRgnAttr));
    grAttrLogo.show = 0;
    /* Set Logo global alpha to 0x7f, it is semi-transparent. */
    grAttrLogo.gAlphaEn = 1;
    grAttrLogo.fgAlhpa = 0x9f;
    grAttrLogo.layer = 3;
    if (IMP_OSD_SetGrpRgnAttr(rHanderLogo, grpNum, &grAttrLogo) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetGrpRgnAttr Logo error !\n");
        return -1;
    }

    /* Cover */
    IMPOSDRgnAttr rAttrCover;
    memset(&rAttrCover, 0, sizeof(IMPOSDRgnAttr));
    rAttrCover.type = OSD_REG_COVER;

    rAttrCover.rect.p0.x = 10;
    rAttrCover.rect.p0.y = 10;
    rAttrCover.rect.p1.x = rAttrCover.rect.p0.x + 19 * OSD_REGION_WIDTH - 1;
    rAttrCover.rect.p1.y = rAttrCover.rect.p0.y + OSD_REGION_HEIGHT - 1;

    rAttrCover.fmt = PIX_FMT_BGRA;
    rAttrCover.data.coverData.color = OSD_IPU_BLACK;
    ret = IMP_OSD_SetRgnAttr(rHanderCover, &rAttrCover);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetRgnAttr Cover error !\n");
        return -1;
    }

    IMPOSDGrpRgnAttr grAttrCover;
    if (IMP_OSD_GetGrpRgnAttr(rHanderCover, grpNum, &grAttrCover) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_GetGrpRgnAttr Cover error !\n");
        return -1;
    }
    memset(&grAttrCover, 0, sizeof(IMPOSDGrpRgnAttr));
    grAttrCover.show = 0;
    /* Disable Cover global alpha, it is absolutely no transparent. */
    grAttrCover.gAlphaEn = 1;
    grAttrCover.fgAlhpa = 0x55;
    grAttrCover.layer = 2;
    if (IMP_OSD_SetGrpRgnAttr(rHanderCover, grpNum, &grAttrCover) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetGrpRgnAttr Cover error !\n");
        return -1;
    }

    /* Rect */
    IMPOSDRgnAttr rAttrRect;
    memset(&rAttrRect, 0, sizeof(IMPOSDRgnAttr));
    rAttrRect.type = OSD_REG_RECT;
    rAttrRect.rect.p0.x = 250;
    rAttrRect.rect.p0.y = 100;
    rAttrRect.rect.p1.x = rAttrRect.rect.p0.x + 100 - 1;
    rAttrRect.rect.p1.y = rAttrRect.rect.p0.y + 100 - 1;
    rAttrRect.fmt = PIX_FMT_MONOWHITE;
    rAttrRect.data.lineRectData.color = OSD_YELLOW;
    rAttrRect.data.lineRectData.linewidth = 5;
    ret = IMP_OSD_SetRgnAttr(rHanderRect, &rAttrRect);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetRgnAttr Rect error !\n");
        return -1;
    }
    IMPOSDGrpRgnAttr grAttrRect;
    if (IMP_OSD_GetGrpRgnAttr(rHanderRect, grpNum, &grAttrRect) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_GetGrpRgnAttr Rect error !\n");
        return -1;
    }
    memset(&grAttrRect, 0, sizeof(IMPOSDGrpRgnAttr));
    grAttrRect.show = 0;
    grAttrRect.layer = 1;
    grAttrRect.scalex = 1;
    grAttrRect.scaley = 1;
    if (IMP_OSD_SetGrpRgnAttr(rHanderRect, grpNum, &grAttrRect) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetGrpRgnAttr Rect error !\n");
        return -1;
    }

    /* Line */
    IMPOSDRgnAttr rAttrLine;
    memset(&rAttrLine, 0, sizeof(IMPOSDRgnAttr));
    rAttrLine.type = OSD_REG_HORIZONTAL_LINE;
    rAttrLine.line.p0.x = 350;
    rAttrLine.line.p0.y = 100;
    rAttrLine.data.lineRectData.color = OSD_RED;
    rAttrLine.data.lineRectData.linewidth = 5;
    rAttrLine.data.lineRectData.linelength = 200;
    ret = IMP_OSD_SetRgnAttr(rHanderLine, &rAttrLine);
    if (ret < 0) {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetRgnAttr Line error !\n");
        return -1;
    }
    IMPOSDGrpRgnAttr grAttrLine;
    if (IMP_OSD_GetGrpRgnAttr(rHanderLine, grpNum, &grAttrLine) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_GetGrpRgnAttr Line error !\n");
        return -1;
    }
    memset(&grAttrLine, 0, sizeof(IMPOSDGrpRgnAttr));
    grAttrLine.show = 0;
    grAttrLine.layer = 1;
    grAttrLine.scalex = 1;
    grAttrLine.scaley = 1;
    if (IMP_OSD_SetGrpRgnAttr(rHanderLine, grpNum, &grAttrLine) < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_SetGrpRgnAttr Line error !\n");
        return -1;
    }

    ret = IMP_OSD_Start(grpNum);
    if (ret < 0) {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_Start TimeStamp, Logo, Cover and Rect error !\n");
        return -1;
    }

    g_SdkVideo_Osd_Hander[grpNum][0] = rHanderFont;
    g_SdkVideo_Osd_Hander[grpNum][1] = rHanderLogo;
    g_SdkVideo_Osd_Hander[grpNum][2] = rHanderCover;
    g_SdkVideo_Osd_Hander[grpNum][3] = rHanderRect;
    g_SdkVideo_Osd_Hander[grpNum][4] = rHanderLine;

    return 0;
}

int ChipSdk_Osd_Exit(int grpNum)
{
    int i;
    int ret;

    for (i = 0; i < 5; i++)
    {
        ret = IMP_OSD_ShowRgn(g_SdkVideo_Osd_Hander[grpNum][i], grpNum, 0);
        if (ret != 0)
        {
            IMP_LOG_ERR(DEF_TAG, "IMP_OSD_ShowRgn() timeStamp error\n");
            return -1;
        }

        ret = IMP_OSD_UnRegisterRgn(g_SdkVideo_Osd_Hander[grpNum][i], grpNum);
        if (ret < 0)
        {
            IMP_LOG_ERR(DEF_TAG, "IMP_OSD_UnRegisterRgn timeStamp error\n");
        }

        IMP_OSD_DestroyRgn(g_SdkVideo_Osd_Hander[grpNum][i]);
    }

    ret = IMP_OSD_DestroyGroup(grpNum);
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "IMP_OSD_DestroyGroup(0) error\n");
        return -1;
    }

    return 0;
}

int Ext_SdkVideo_Init(void)
{
    g_SdkVideo_Start_Venc = DEF_COM_FALSE;

    int i;
    int ret;

    /* Step.1 System init */
    ret = ChipSdk_System_Init();
    if (ret < 0) {
        IMP_LOG_ERR(DEF_TAG, "IMP_System_Init() failed\n");
        return -1;
    }

    /* Step.2 FrameSource init */
    ret = ChipSdk_FrameSource_Init();
    if (ret < 0) {
        IMP_LOG_ERR(DEF_TAG, "FrameSource init failed\n");
        return -1;
    }

    /* Step.3 Encoder init */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = IMP_Encoder_CreateGroup(chn[i].index);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_CreateGroup(%d) error !\n", chn[i].index);
                return -1;
            }
        }
    }

    ret = ChipSdk_Encoder_Init();
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "Encoder init failed\n");
        return -1;
    }

    /* Step.4 OSD init */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            if (IMP_OSD_CreateGroup(i) < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_OSD_CreateGroup(%d) error !\n", i);
                return -1;
            }
        }
    }

    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = ChipSdk_Osd_Init(i);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "OSD init failed\n");
                return -1;
            }
        }
    }

    ret = IMP_IVS_CreateGroup(0);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG, "IMP_IVS_CreateGroup(%d) failed\n", 0);
        return -1;
    }

    /* Step.5 Bind */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            IMPCell osdcell;

            osdcell.deviceID = DEV_ID_OSD;
            osdcell.groupID = i;
            osdcell.outputID = 0;

#if CMAKE_USE_CHIP_AI
            if(i == IVS_CHN_ID)
            {
                IMPCell ivs_cell = {DEV_ID_IVS, 0, 0};

                ret = IMP_System_Bind(&chn[i].framesource_chn, &ivs_cell);
                if (ret < 0) {
                    IMP_LOG_ERR(DEF_TAG, "Bind FrameSource channel.1 output.1 and ivs0 failed\n");
                    return -1;
                }
            }
#else
            if(i == IVS_CHN_ID)
            {
                IMPCell ivs_cell = {DEV_ID_IVS, 0, 0};

                ret = IMP_System_Bind(&chn[i].framesource_chn, &ivs_cell);
                if (ret < 0) {
                    IMP_LOG_ERR(DEF_TAG, "Bind FrameSource channel.1 output.1 and ivs0 failed\n");
                    return -1;
                }

                ret = IMP_System_Bind(&ivs_cell, &osdcell);
                if (ret < 0) {
                    IMP_LOG_ERR(DEF_TAG, "Bind FrameSource channel%d and Encoder failed\n",i);
                    return -1;
                }

                ret = IMP_System_Bind(&osdcell, &chn[i].imp_encoder);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "Bind OSD and Encoder failed\n");
                    return -1;
                }
            }
#endif
            else
            {

                ret = IMP_System_Bind(&chn[i].framesource_chn, &osdcell);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "Bind FrameSource channel0 and OSD failed\n");
                    return -1;
                }

                ret = IMP_System_Bind(&osdcell, &chn[i].imp_encoder);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "Bind OSD and Encoder failed\n");
                    return -1;
                }
            }
        }
    }

    Ext_SdkOsd_Init();
    Ext_SdkNightMonitor_Init();

    /* Step.5 Stream On */
    IMP_FrameSource_SetFrameDepth(0, 0);
    ret = ChipSdk_FrameSource_StreamOn();
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "ImpStreamOn failed\n");
        return -1;
    }

#if !CMAKE_PRODUCT_TEST
    ret = ChipSdk_Jpeg_Init();
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG, "Encoder init failed\n");
        return -1;
    }
#endif

    return 0;
}

void Ext_SdkVideo_Start(void)
{
    g_SdkVideo_Start_Venc = DEF_COM_TRUE;
}

int Ext_SdkVideo_Exit(void)
{
    int i;
    int ret;

    ret = ChipSdk_Jpeg_Exit();
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG, "Encoder jpeg exit failed\n");
        return -1;
    }

    /* Exit sequence as follow */
    /* Step.a Stream Off */
    ret = ChipSdk_FrameSource_StreamOff();
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "FrameSource StreamOff failed\n");
        return -1;
    }

    /* Step.b UnBind */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            IMPCell osdcell;
            osdcell.deviceID = DEV_ID_OSD;
            osdcell.groupID = i;
            osdcell.outputID = 0;

#if CMAKE_USE_CHIP_AI
            if(IVS_CHN_ID == i)
            {
                IMPCell ivs_cell = {DEV_ID_IVS, 0, 0};

                ret = IMP_System_UnBind(&chn[i].framesource_chn, &ivs_cell);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "UnBind FrameSource channel%d and Encoder failed\n",i);
                    return -1;
                }
            }
#else
            if(IVS_CHN_ID == i)
            {
                IMPCell ivs_cell = {DEV_ID_IVS, 0, 0};

                ret = IMP_System_UnBind(&osdcell, &chn[i].imp_encoder);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "UnBind FrameSource channel%d and Encoder failed\n",i);
                    return -1;
                }

                ret = IMP_System_UnBind(&ivs_cell, &osdcell);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "UnBind FrameSource channel%d and Encoder failed\n",i);
                    return -1;
                }

                ret = IMP_System_UnBind(&chn[i].framesource_chn, &ivs_cell);
                if (ret < 0)
                {
                    IMP_LOG_ERR(DEF_TAG, "UnBind FrameSource channel%d and Encoder failed\n",i);
                    return -1;
                }
            }
#endif
            else
            {
                ret = IMP_System_UnBind(&osdcell, &chn[i].imp_encoder);
                if (ret < 0) {
                    IMP_LOG_ERR(DEF_TAG, "Bind OSD and Encoder failed\n");
                    return -1;
                }

                ret = IMP_System_UnBind(&chn[i].framesource_chn, &osdcell);
                if (ret < 0) {
                    IMP_LOG_ERR(DEF_TAG, "UnBind FrameSource and OSD failed\n");
                    return -1;
                }
            }


        }
    }

    ret = IMP_IVS_DestroyGroup(0);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG, "IMP_IVS_DestroyGroup failed\n");
        return -1;
    }

    /* Step.c OSD exit */
    for (i = 0; i < FS_CHN_NUM; i++)
    {
        if (chn[i].enable)
        {
            ret = ChipSdk_Osd_Exit(i);
            if (ret < 0) {
                IMP_LOG_ERR(DEF_TAG, "OSD exit failed\n");
                return -1;
            }
        }
    }

#if !CMAKE_USE_CHIP_AI
    Ext_SdkMotionDetect_Exit();
#endif

    /* Step.c Encoder exit */
    ret = ChipSdk_Encoder_Exit();
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "Encoder exit failed\n");
        return -1;
    }

    /* Step.d FrameSource exit */
    ret = ChipSdk_FrameSource_Exit();
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "FrameSource exit failed\n");
        return -1;
    }

    /* Step.e System exit */
    ret = ChipSdk_System_Exit();
    if (ret < 0)
    {
        IMP_LOG_ERR(DEF_TAG, "ChipSdk_System_Exit() failed\n");
        return -1;
    }

    return 0;
}

int Ext_SdkMediaCom_GetVideoData(int chn_num,pStSdkVideoInfo info)
{
    if((chn_num == CH1_INDEX) && (g_SdkVideo_Pic_Flag == DEF_COM_TRUE))
    {
        usleep(10);
        return DEF_COM_FAILED;
    }

    int ret;
    fd_set readfds;
    struct timeval selectTimeout;

    FD_ZERO(&readfds);
    FD_SET(g_SdkVideo_VencFd[chn_num], &readfds);

    selectTimeout.tv_sec = 0;
    selectTimeout.tv_usec = (10 * 1000);

    ret = select(g_SdkVideo_MaxVencFd + 1, &readfds, NULL, NULL, &selectTimeout);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG,"select failed:%s\n", strerror(errno));
        return -1;
    }
    else if (ret == 0)
    {
        return -1;
    }
    else
    {
        if (chn[chn_num].enable && FD_ISSET(g_SdkVideo_VencFd[chn_num], &readfds))
        {
            memset(&g_SdkVideo_Stream,0,sizeof(g_SdkVideo_Stream));
            ret = IMP_Encoder_GetStream(chn_num, &g_SdkVideo_Stream, 1);
            if (ret < 0)
            {
                IMP_LOG_ERR(DEF_TAG, "IMP_Encoder_GetStream(%d) failed\n", chn_num);
                return DEF_COM_FAILED;
            }

            int i,nr_pack;
            int v_len = 0;

            nr_pack = g_SdkVideo_Stream.packCount;
            memset(g_SdkVideo_Buf,0,sizeof(g_SdkVideo_Buf));
            for (i = 0; i < nr_pack; i++)
            {
                IMPEncoderPack *pack = &g_SdkVideo_Stream.pack[i];

                memcpy(g_SdkVideo_Buf + v_len,
                       (Com_pu8)g_SdkVideo_Stream.virAddr + pack->offset,pack->length);
                v_len += pack->length;
                info->type = (pack->sliceType == IMP_ENC_SLICE_I) ? SDK_FRAME_TYPE_I : SDK_FRAME_TYPE_P;
                info->pts = pack->timestamp;
            }

            info->buf = (Com_pu8)g_SdkVideo_Buf;
            info->size = v_len;
        }
    }

    return DEF_COM_SUCCESS;
}

void Ext_SdkMediaCom_ReleaseVideoData(int chnnel)
{
    if (chn[chnnel].enable)
    {
        IMP_Encoder_ReleaseStream(chnnel, &g_SdkVideo_Stream);
    }
}

void Ext_SdkVideo_QRCodeStart(void)
{
    int ret;

    ret = IMP_FrameSource_SetFrameDepth(CH1_INDEX, 1);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG, "IMP_FrameSource_SetFrameDepth failed\n");
        return;
    }
}

void Ext_SdkVideo_QRCodeStop(void)
{
    int ret;

    ret = IMP_FrameSource_SetFrameDepth(CH1_INDEX, 0);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG,"IMP_FrameSource_SetFrameDepth failed\n");
        return;
    }
}

int Ext_SdkMediaCom_GetQRCodeData(pStSdkQrcodeInfo info)
{
    int ret;

    ret = IMP_FrameSource_GetFrame(CH1_INDEX, &g_SdkVideo_Frame_Bak);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG, "IMP_FrameSource_GetFrame failed\n");
        return DEF_COM_FAILED;
    }

    info->buf = (Com_pu8)g_SdkVideo_Frame_Bak->virAddr;

    return DEF_COM_SUCCESS;
}

void Ext_SdkMediaCom_ReleaseQRCodeData(void)
{
    /* Release the acquired YUV data */
    IMP_FrameSource_ReleaseFrame(CH1_INDEX, g_SdkVideo_Frame_Bak);
}

void Ext_SdkMediaCom_RequestIDR(void)
{
    PRT_INFO(DEF_TAG,"set I frame\n");

    int i;

    for (i = 0; i <  FS_CHN_NUM; i++)
    {
        if(i == CH2_INDEX)
        {
            continue;
        }

        if (chn[i].enable)
        {
            IMP_Encoder_RequestIDR(chn[i].index);
        }
    }
}

int SdkVideo_SaveStream(int fd, IMPEncoderStream *stream)
{
    int ret, i, nr_pack = stream->packCount;

    for (i = 0; i < nr_pack; i++)
    {
        IMPEncoderPack *pack = &stream->pack[i];
        if(pack->length)
        {
            uint32_t remSize = stream->streamSize - pack->offset;
            if(remSize < pack->length)
            {
                ret = write(fd, (void *)(stream->virAddr + pack->offset), remSize);
                if (ret != remSize)
                {
                    PRT_ERR(DEF_TAG, "stream write ret(%d) != pack[%d].remSize(%d) error:%s\n",
                               ret, i, remSize, strerror(errno));
                    return -1;
                }

                ret = write(fd, (void *)stream->virAddr, pack->length - remSize);
                if (ret != (pack->length - remSize))
                {
                    PRT_ERR(DEF_TAG, "stream->virAddr:%x stream write ret(%d) != pack[%d].(length-remSize)(%d) error:%s\n",
                               stream->virAddr, ret, i, (pack->length - remSize), strerror(errno));
                    return -1;
                }
            }
            else
            {
                ret = write(fd, (void *)(stream->virAddr + pack->offset), pack->length);
                if (ret != pack->length) {
                    PRT_ERR(DEF_TAG, "stream write ret(%d) != pack[%d].length(%d) error:%s\n",
                               ret, i, pack->length, strerror(errno));
                    return -1;
                }
            }
        }
    }
    return 0;
}

void Ext_SdkMediaCom_SavePic(void)
{
    g_SdkVideo_Pic_Flag = DEF_COM_TRUE;

    int i = 0, ret;
    char snap_path[64];

    if (chn[i].enable)
    {
        ret = IMP_Encoder_StartRecvPic(4 + chn[i].index);
        if (ret < 0)
        {
            PRT_ERR(DEF_TAG, "IMP_Encoder_StartRecvPic(%d) failed\n", 4 + chn[i].index);
            return;
        }

        sprintf(snap_path,"%s/%s",DEF_COM_SAVE_JEP_PATH,DEF_COM_JPEG_NAME);
        //PRT_NORMAL("Open Snap file %s ", snap_path);
        int snap_fd = open(snap_path, O_RDWR | O_CREAT | O_TRUNC, 0777);
        if (snap_fd < 0)
        {
            PRT_ERR(DEF_TAG, "failed: %s\n", strerror(errno));
            return;
        }

        /* Polling JPEG Snap, set timeout as 1000msec */
        ret = IMP_Encoder_PollingStream(4 + chn[i].index, 1000);
        if (ret < 0)
        {
            PRT_ERR(DEF_TAG, "Polling stream timeout\n");
            close(snap_fd);
            return;
        }

        IMPEncoderStream stream;
        /* Get JPEG Snap */
        ret = IMP_Encoder_GetStream(chn[i].index + 4, &stream, 1);
        if (ret < 0)
        {
            PRT_ERR(DEF_TAG, "IMP_Encoder_GetStream() failed\n");
            close(snap_fd);
            return;
        }

        ret = SdkVideo_SaveStream(snap_fd, &stream);
        if (ret < 0)
        {
            close(snap_fd);
            return;
        }

        IMP_Encoder_ReleaseStream(4 + chn[i].index, &stream);
        close(snap_fd);

        ret = IMP_Encoder_StopRecvPic(4 + chn[i].index);
        if (ret < 0)
        {
            PRT_ERR(DEF_TAG, "IMP_Encoder_StopRecvPic() failed\n");
            return;
        }
    }

    g_SdkVideo_Pic_Flag = DEF_COM_FALSE;
    PRT_NORMAL("save jpeg end\n");
}

int Ext_SdkMediaCom_SetFlip(int mode)
{
    Com_s32 ret;
    Com_s32 val;
    IMPISPHVFLIPAttr attr;

    memset(&attr,0,sizeof(attr));
    IMP_ISP_Tuning_GetHVFLIP(IMPVI_MAIN,&attr);

    ret = Ext_InSdkIniBasic_GetVal(INI_BASIC_VIDEO_FLIP);
    if(ret)
    {
        val = (mode == 1) ? 0 : 3;
    }
    else
    {
        val = (mode == 1) ? 3 : 0;
    }

    attr.sensor_mode = val;
    IMP_ISP_Tuning_SetHVFLIP(IMPVI_MAIN,&attr);

    return mode;
}

void Ext_SdkMediaCom_SetVpssEffect(EnSdkVideoEffect effect,int val)
{
    //Com_s32 ret = 0;

    PRT_INFO(DEF_TAG,"effect: %d,val: %d\n",effect,val);

    switch(effect)
    {
    case VIDEO_EFFECT_BRIGHTNESS :
    {
        //int s_val = val - 50;
    }
        break;

    case VIDEO_EFFECT_CONTRAST :
    {
        //int s_val = val - 50;

    }
        break;

    default :
        printf("no this type\n");
        break;
    }
}

int Sdk_Video_Get_NV12_Frame(void)
{
    int chnNum = chn[CH1_INDEX].index;
    int i = 0, ret = 0;
    int fd = -1;
    char framefilename[64];
    IMPFrameInfo *frame = NULL;

    sprintf(framefilename, "/mnt/config/record/nv12s/frame_%d_%d.nv12", chn[CH1_INDEX].fs_chn_attr.picWidth, chn[CH1_INDEX].fs_chn_attr.picHeight);

    fd = open(framefilename, O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    if (fd < 0)
    {
        PRT_ERR(DEF_TAG,"open %s failed:%s\n", framefilename, strerror(errno));
        goto err_open_framefilename;
    }

    ret = IMP_FrameSource_SetFrameDepth(chnNum, chn[CH1_INDEX].fs_chn_attr.nrVBs * 2);
    if (ret < 0)
    {
        PRT_ERR(DEF_TAG,"IMP_FrameSource_SetFrameDepth(%d,%d) failed\n", chnNum, chn[CH1_INDEX].fs_chn_attr.nrVBs * 2);
        goto err_IMP_FrameSource_SetFrameDepth_1;
    }

    for (i = 0; i < NR_FRAMES_TO_SAVE; i++)
    {
        //printf("IMP_FrameSource_GetFrame(%d) i=%d\n",chnNum,i);
        ret = IMP_FrameSource_GetFrame(chnNum, &frame);
        if (ret < 0)
        {
            PRT_ERR(DEF_TAG,"IMP_FrameSource_GetFrame(%d) i=%d failed\n", chnNum, i);
            goto err_IMP_FrameSource_GetFrame_i;
        }

        if (NR_FRAMES_TO_SAVE / 2 == i)
        {
            if (write(fd, (void *)frame->virAddr, frame->size) != frame->size)
            {
                PRT_ERR(DEF_TAG,"chnNum=%d write frame i=%d failed\n", chnNum, i);
                goto err_write_frame;
            }
            break;
        }

        ret = IMP_FrameSource_ReleaseFrame(chnNum, frame);
        if (ret < 0)
        {
            PRT_ERR(DEF_TAG,"IMP_FrameSource_ReleaseFrame(%d) i=%d failed\n", chnNum, i);
            goto err_IMP_FrameSource_ReleaseFrame_i;
        }
    }

    IMP_FrameSource_SetFrameDepth(chnNum, 0);
    close(fd);

    return 0;

err_IMP_FrameSource_ReleaseFrame_i:
err_write_frame:
    IMP_FrameSource_ReleaseFrame(chnNum, frame);
err_IMP_FrameSource_GetFrame_i:
    goto err_IMP_FrameSource_SetFrameDepth_1;
    IMP_FrameSource_SetFrameDepth(chnNum, 0);
err_IMP_FrameSource_SetFrameDepth_1:
    close(fd);
err_open_framefilename:
    return -1;
}
